package com.bestcem.xm.member.handler.member;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.constant.AppRequestErrorCode;
import com.bestcem.xm.common.core.constant.AppResourceErrorCode;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.uitls.CommonUtil;
import com.bestcem.xm.member.controller.param.HttpCreateMemberParam;
import com.bestcem.xm.member.controller.param.HttpUpdateHttpMemberParam;
import com.bestcem.xm.member.dao.MemberDao;
import com.bestcem.xm.member.dao.SourceCardDao;
import com.bestcem.xm.member.entity.mysql.SourceCardDo;
import com.bestcem.xm.member.entity.pojo.MemberDO;
import com.bestcem.xm.member.enums.CardSourceTypeEnum;
import com.bestcem.xm.member.enums.FootprintTypeEnum;
import com.bestcem.xm.member.enums.MemberTypeEnum;
import com.bestcem.xm.member.enums.NewMemberStatusEnum;
import com.bestcem.xm.member.mq.message.MemberMessage;
import com.bestcem.xm.member.service.FootprintService;
import com.bestcem.xm.member.service.GroupService;
import com.bestcem.xm.member.service.dto.OrganizationDTO;
import com.bestcem.xm.member.service.param.AddFootprintParam;
import com.bestcem.xm.member.util.CheckUtil;
import com.bestcem.xm.member.util.MemberUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;

/**
 * 个人联系人
 *
 * @author yf.wang <yf.wang@idiaoyan.com>
 * @version V1.0
 * @date 2021/7/16
 */
@Slf4j
@Component
public class IndividualMemberHandler extends BaseMemberHandle {

    @Resource
    private MemberDao memberDao;

    @Resource
    private SourceCardDao sourceCardDao;

    @Autowired
    private FootprintService footprintService;

    @Resource
    private GroupService groupService;

    @Override
    public ServiceResult<String> checkParams(HttpCreateMemberParam param) {
        String email = param.getEmail();
        String mobile = param.getMobile();
        String outNo = param.getOutNo();
        String appId = param.getAppId();
        String openId = param.getOpenId();
        if (StrUtil.isEmpty(email) && StrUtil.isEmpty(mobile) && StrUtil.isEmpty(outNo)) {
            // AppID和OpenID必须同时存在
            if(StrUtil.isEmpty(appId) || StrUtil.isEmpty(openId)){
                return ServiceResult.fail("手机号、邮箱、外部编号、微信appID+openID至少填写一个");
            }
        }
        if (StrUtil.isEmpty(appId)^StrUtil.isEmpty(openId)) {
            String errorMessage = "微信appID+openID必须同时存在";
            return ServiceResult.<String>fail(errorMessage).setErrorCode(String.valueOf(AppRequestErrorCode.PARAM_FORMAT));
        }
        if(StringUtils.hasText(appId) && StringUtils.hasText(openId)){
            if(!CheckUtil.checkAppIdFormat(appId, MemberTypeEnum.INDIVIDUAL.getIndex()).isSuccess()){
                return ServiceResult.fail("appID不能超过128位");
            }
            if(!CheckUtil.checkOpenIdFormat(openId, MemberTypeEnum.INDIVIDUAL.getIndex()).isSuccess()){
                return ServiceResult.fail("openID不能超过128位");
            }
        }

        return ServiceResult.success();
    }

    @Override
    public ServiceResult<String> save(HttpCreateMemberParam param) {
        // 对指定参数进行非空校验
        ServiceResult<String> checkParamsResult = checkParams(param);
        if (!checkParamsResult.isSuccess()) {
            return ServiceResult.<String>fail(checkParamsResult.getMsg())
                    .setErrorCode(String.valueOf(AppRequestErrorCode.PARAM_LOST));
        }
        // 校验姓名
        String name = param.getName();
        if (StringUtils.hasText(name) && name.length() > 50) {
            return ServiceResult.<String>fail("姓名长度不能超过50")
                    .setErrorCode(String.valueOf(AppRequestErrorCode.PARAM_RANGE));
        }
        // 检查一下数据的重复性
        ServiceResult<String> checkMobileAndEmailResult =
                this.checkUniqueValue(param.getMobile(), param.getEmail(), param.getMemberType(),
                        param.getOrgId(), param.getOutNo(), param.getAppId(), param.getOpenId());
        if (!checkMobileAndEmailResult.isSuccess()) {
            return ServiceResult.<String>fail(checkMobileAndEmailResult.getData(), checkMobileAndEmailResult.getMsg())
                    .setErrorCode(checkMobileAndEmailResult.getErrorCode());
        }
        //获取序号
        String memberNo = getMemberNo(param.getOrgId(), param.getMemberType());

        // 创建联系人
        MemberDO member = MemberUtil.httpMemberBaseParamToMemberDo(param);
        member.setMemberNo(memberNo);
        member.setStatus(NewMemberStatusEnum.MEMBER_STATUS_ACTIVATED.getIndex());
        member.setSource("manual");
        // 分组同步令牌
        member.setGroupSyncToken(CommonUtil.getUUID());
        member = memberDao.manualSave(member);
        // 异步更新联系人分组信息
        groupService.sendMemberCreationUpdMessage(member.getOrgId(), member.getId(), member.getGroupSyncToken());
        // 获取组织信息
        ServiceResult<OrganizationDTO> organization = getOrganization(param.getOrgId());
        if (!organization.isSuccess()) {
            return ServiceResult.<String>fail(checkParamsResult.getMsg())
                    .setErrorCode("-1");
        }
        OrganizationDTO dto = organization.getData();
        //若 手机或者邮箱是内部联系人
        String identityType = memberUtil.getIdentityType(param.getMobile(), param.getOrgId(), param.getEmail());

        // 推送创建的联系人
        MemberMessage message = MemberUtil.memberDoToMemberMessage(member);
        message.setIdentityType(identityType);
        message.setOrgCode(dto.getCode());
        message.setOrgName(dto.getName());
        memberUtil.publishCreateMember(message);

        // 推送成为联系人足迹点
        JSONObject footprint = new JSONObject();
        footprint.put("title", "成为联系人");
        AddFootprintParam addFootprintParam = new AddFootprintParam();
        addFootprintParam.setOrgId(param.getOrgId());
        addFootprintParam.setMemberId(member.getId());
        addFootprintParam.setType(FootprintTypeEnum.MEMBER.getIndex());
        addFootprintParam.setSourceKey(member.getId());
        addFootprintParam.setContent(footprint);
        addFootprintParam.setFootprintTime(member.getCreateTime());
        footprintService.publishFootprint(addFootprintParam);

        // 创建名片 手工创建&编辑个人联系人只保留一张名片
        SourceCardDo card = new SourceCardDo();
        card.setMemberId(member.getId());
        card.setSource(CardSourceTypeEnum.MANUAL.getIndex());
        card.setOrgId(param.getOrgId());

        //  获取该联系人的名片
        List<SourceCardDo> sourceCards = sourceCardDao.findByMid(member.getId());
        if (CollUtil.isNotEmpty(sourceCards)) {
            for (SourceCardDo sourceCard : sourceCards) {
                if (sourceCard.getSource() == CardSourceTypeEnum.MANUAL.getIndex()) {
                    return ServiceResult.success(member.getId());
                }
            }
        }
        String cardNo = memberNo + "-" + NumberUtil.decimalFormat("000", sourceCards.size() + 1);
        card.setSerial(cardNo);
        card.setData(JSONObject.toJSONString(param));
        sourceCardDao.save(card);

        return ServiceResult.success(member.getId());
    }

    public ServiceResult<String> checkUniqueValue(String mobile, String email, Integer memberType, String orgId,
                                                  String outNo, String appId, String openId) {
        ServiceResult<String> superResult = super.checkUniqueValue(mobile, email, memberType, orgId, outNo);

        if(superResult.isSuccess() && (StringUtils.hasText(appId) && StringUtils.hasText(openId))){
            MemberDO member = memberDao.findByAppIdAndOpenId(orgId, MemberTypeEnum.INDIVIDUAL.getIndex(), appId, openId);
            if(member != null){
                if(log.isErrorEnabled()){
                    log.error("联系人appid+openid已存在:{}, {}", appId, openId);
                }
                return ServiceResult.<String>fail(member.getId(), "该类型中，联系人appid和openid已存在")
                        .setErrorCode(String.valueOf(AppResourceErrorCode.FOUND));
            }
        }
        return superResult;
    }

    /**
     * 保存 通过excel导入的联系人
     *
     * @param member
     */
    @Override
    public ServiceResult<Void> saveImportMember(MemberDO member, Integer quota) {
        // fixBug 20210917 只有个人联系人才限额
        if (quota != -1) {
            // 获取个人联系人的数量
            Long num = memberDao.countIndividualMember(member.getOrgId());
            if (log.isInfoEnabled()) {
                log.info("该组织 {} 个人联系人的数量 {}", member.getOrgId(), num);
            }
            if (num >= quota) {
                return ServiceResult.<Void>fail("已达套餐限额");
            }
        }

        member = memberDao.importSave(member);
        // 获取组织信息
        ServiceResult<OrganizationDTO> organization = getOrganization(member.getOrgId());
        if (!organization.isSuccess()) {
            return ServiceResult.fail(organization.getMsg());
        }
        OrganizationDTO dto = organization.getData();

        //若 手机或者邮箱是内部联系人
        String identityType = memberUtil.getIdentityType(member.getPhone(), member.getOrgId(), member.getEmail());

        // 推送成为联系人足迹点
        JSONObject footprint = new JSONObject();
        footprint.put("title", "成为联系人");
        AddFootprintParam addFootprintParam = new AddFootprintParam();
        addFootprintParam.setOrgId(member.getOrgId());
        addFootprintParam.setMemberId(member.getId());
        addFootprintParam.setType(FootprintTypeEnum.MEMBER.getIndex());
        addFootprintParam.setSourceKey(member.getId());
        addFootprintParam.setContent(footprint);
        addFootprintParam.setFootprintTime(member.getCreateTime());
        footprintService.publishFootprint(addFootprintParam);

        // 推送创建的联系人
        MemberMessage message = MemberUtil.memberDoToMemberMessage(member);
        message.setIdentityType(identityType);
        message.setIdentityType(identityType);
        message.setOrgCode(dto.getCode());
        message.setOrgName(dto.getName());
        memberUtil.publishCreateMember(message);

        // 创建名片
        SourceCardDo card = new SourceCardDo();
        card.setMemberId(member.getId());
        card.setSource(CardSourceTypeEnum.FILE.getIndex());
        card.setOrgId(member.getOrgId());
        String memberNo = member.getMemberNo();

        String cardNo = memberNo + "-" + "000";
        card.setSerial(cardNo);
        card.setData(JSONObject.toJSONString(member));
        sourceCardDao.save(card);
        return ServiceResult.success();
    }

    @Override
    public XmResultJson<String> updateManualMember(MemberDO member,
                                                   HttpUpdateHttpMemberParam param) {
        // 用户手机号，微信userid,支付宝userid,邮箱, appid+openid不能同时为空

        // 对 email， mobile， openid，appid+openid， alipay_user_id 进行校验
        ServiceResult<String> checkResult = checkUpdateParam(member, param);
        if (!checkResult.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(checkResult.getErrorCode()), checkResult.getMsg());
        }
        // 校验姓名
        String name = param.getName();
        if (StringUtils.hasText(name) && name.length() > 50) {
            return XmResultJson.fail(AppRequestErrorCode.PARAM_RANGE, "姓名长度不能超过50");
        }
        // 隐藏相似的数据也需要更改
        List<MemberDO> similarlyMembers = this.getSimilarlyMembers(member);
        ServiceResult<String> checkFieldValueFormatResult = checkFieldValueFormatValid(param.getFieldValues());
        if (!checkFieldValueFormatResult.isSuccess()) {
            return XmResultJson.fail(AppRequestErrorCode.PARAM_LOST, checkFieldValueFormatResult.getMsg());
        }

        // 获取组织信息
        ServiceResult<OrganizationDTO> organization = getOrganization(param.getOrgId());
        if (!organization.isSuccess()) {
            return XmResultJson.fail(-1, organization.getMsg());
        }
        OrganizationDTO dto = organization.getData();
        if (CollectionUtil.isNotEmpty(similarlyMembers)) {
            similarlyMembers.forEach(similarlyMember -> {
                MemberDO updateMember = this.toMemberDoForUpdate(param);
                updateMember.setId(similarlyMember.getId());
                updateMember.setMemberType(MemberTypeEnum.INDIVIDUAL.getIndex());
                updateMember.setCreateTime(similarlyMember.getCreateTime());
                updateMember.setOrgId(similarlyMember.getOrgId());
                updateMember.setUnionId(similarlyMember.getUnionId());
                updateMember(updateMember);
                String identityType = memberUtil.getIdentityType(updateMember.getPhone(),
                        updateMember.getOrgId(), updateMember.getEmail());
                // 推送
                MemberMessage message = MemberUtil.memberDoToMemberMessage(updateMember);
                message.setStatus(similarlyMember.getStatus());
                message.setIdentityType(identityType);
                message.setOrgCode(dto.getCode());
                message.setOrgName(dto.getName());
                memberUtil.publishUpdateMember(message);
            });
        }
        return XmResultJson.success(param.getId());
    }

    /**
     * 获取相似联系人
     * @param member
     * @return
     */
    private List<MemberDO> getSimilarlyMembers(MemberDO member){
        List<MemberDO> similarlyMembers = getSimilarlyMembers(member.getOrgId(), member.getPhone(),
                member.getEmail(), member.getAliPayUserId(), member.getOpenId(), member.getMemberType(), member.getOutNo());

        if(StringUtils.hasText(member.getAppId()) && StringUtils.hasText(member.getOpenId())){
            List<MemberDO> appIdAndOpenIdMembers = memberDao.listByAppIdAndOpenId(member.getOrgId(), member.getMemberType(),
                    member.getAppId(), member.getOpenId());
            similarlyMembers.addAll(appIdAndOpenIdMembers);
        }
        return similarlyMembers;
    }

    @Override
    public void updateMember(MemberDO member) {
        // 分组同步令牌
        member.setGroupSyncToken(CommonUtil.getUUID());
        memberDao.updateMember(member, true);
        // 异步更新联系人分组信息
        groupService.sendMemberCreationUpdMessage(member.getOrgId(), member.getId(), member.getGroupSyncToken());
    }
}
